package com.cjy.queueArray;

/**
 * @Author cjy
 * @Date 2022/6/26 16:09
 * @Version 1.0
 * 环形队列
 */
public class CircleArrayQueue {
    public static void main(String[] args) {
        //测试数组环形队列
        System.out.println();
        // 创建一个队列
        CircleArray circleArray = new CircleArray(3);
        // 测试对象中的方法
//        arrayQueue.showQueue();
        circleArray.addQueue(2);
        // 取数据的时候会报异常 所以需要用try-catch来捕获异常
        try {
            int res = circleArray.getQueue();
            System.out.printf("取出的数据是%d",res);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class CircleArray{
    private int maxSize; // 数组的最大容量
    private int front; //队列头,初始值为0，arr[front]
    private int rear; // 队列尾,初始值也是0，但是为实际下标位置+1
    private int[] arr ; // 这里是用数组来实现队列

    public CircleArray(int arrMaxSize) {
        this.maxSize = arrMaxSize;
        arr = new int[maxSize];
    }

    /**
     * 判断环形队列是否已满——》
     * 实践思路：这里使用了算法(rear + 1) % maxSize == front
     */
    public boolean isFull(){
        // 🐳双等号是判断、单等号是赋值
        return (rear + 1) % maxSize == front;
    }

    /**
     * 判断是否为空
     */
    public boolean isEmpty(){
        return rear == front;
    }

    /**
     * 将数据添加到环形队列中
     * 🐳难点在于当到了队列最后的时候，指针rear需要返回到队列头上的空位
     * 解决办法是 %取模
     */
    public void addQueue(int n){
        //判断环型队列是否已满
        if(isFull()){
            System.out.println("队列已满，需要扩容");
            return;
        }
        arr[rear]=n;
        // 指针的位置，判断指针是否会返回到队列的前面,通过取模来解决,否则会有索引越界
        rear = (rear + 1) % maxSize;
    }

    /**
     * 取出数据
     */
    public int getQueue(){
        //判断环型队列是否为空
        if (isEmpty()){
            // 队列为空抛出异常
            throw new RuntimeException("队列为空，无法取数据");
        }
        //需要分析出front指向队列中的第一个元素
        int value =arr[front];
        front =(front + 1)%maxSize;
        return value;
    }
    /**
     * 显示队列的所有数据
     */
    public void showQueue(){
        //遍历
        if (isEmpty()){
            System.out.println("队列为空，没有数据");
            return;
        }
        // 🐳请求环型数组中的有效元素个数，然后才能将其遍历出来
        // 同时还要获取到有效值的下标
        for (int i =front ; i<front+size() ; i++){
            //获取有效值的下标位置
            System.out.printf("arr[%d]=%d\n", i % maxSize,arr[i % maxSize]);
        }

    }
    /**
     * 求出当前队列中的有效值的个数
     * 🐳难点
     */
    public int size(){
        return (rear + maxSize - front)% maxSize;
    }

    /**
     * 显示队列中的第一个添加的元素
     */
    public int headQueue(){
        if (isEmpty()){
            throw new RuntimeException("队列为空，无法取得数据");
        }
        return arr[front];
    }

}
